// Main.cpp (c) 2011 JV Software
//

#include <iostream>
#include <fstream>
#include <string>

#include <d3dcompiler.h>

using namespace std;

string shaderpath = "";

/*
================
FS_GetPathFromFileName
================
*/
__forceinline string FS_GetFileName( string path ) {
	string sect = "";

	for(int i = 0; i < path.size(); i++ ) {
		sect += path[i];

		if(path[i] == '\\' || path[i] == '/') {
			sect = "";
		}
		
	}

	return sect;
}

/*
================
FS_GetPathFromFileName
================
*/
__forceinline string FS_GetPathFromFileName( string path ) {
	string dir = "", sect = "";

	for(int i = 0; i < path.size(); i++ ) {
		sect += path[i];

		if(path[i] == '\\' || path[i] == '/') {
			dir += sect;
			sect = "";
		}
		
	}

	dir += '\\';

	return dir;
}

/*
=============
FS_ReadFile
=============
*/
__forceinline string FS_ReadFile( string path ) {
	string buffer;

	string line;
	ifstream myfile (path.c_str());
	while ( myfile.good() ) {
		getline (myfile,line);
		buffer += line;
		buffer += "\n";
	}
	myfile.close();

	if(buffer.size() <= 0) {
		cout << "ERROR: Failed to open " << path << endl;
		return NULL;
	}
	
	return buffer;
}

//
// D3DInclude
//
struct D3DInclude : public ID3DInclude {
public:
	virtual HRESULT __stdcall Open( D3D_INCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes ) {
		static string parent = "";

		if(pParentData != NULL) {
			parent += (const char *)pParentData;
		}

		parent += FS_ReadFile( shaderpath + pFileName );

		*ppData = (LPCVOID *)parent.c_str();
		*pBytes = (UINT)parent.size();

		return S_OK;
	}

	virtual HRESULT __stdcall Close(LPCVOID pData) {
		return S_OK;
	}
};

/*
=================
main
=================
*/

int main( int argc, char **argv ) {
	string shaderBuffer;
	D3DInclude shaderInclude;
	ID3DBlob *shaderBlob, *shaderFinalBlob, *errorBlob;

	// Ensure we have the right number of arguments.
	if(argc <= 1) {
		cout << "EffectCompiler.exe <effect>" << endl;
		return 0;
	}

	cout << "Compiling " << FS_GetFileName( argv[1] ) << endl;

	// Read the shader from the harddrive.
	string path = argv[1];
	string outpath = argv[1];

	outpath += ".feffect";
	path += ".hlsl";

	shaderpath = FS_GetPathFromFileName( outpath );

	shaderBuffer = FS_ReadFile( path.c_str() );

	// Preprocess the hlsl shader.
	if(FAILED(D3DPreprocess(shaderBuffer.c_str(), shaderBuffer.size(),path.c_str(), NULL, &shaderInclude, &shaderBlob, &errorBlob ))) {
		cout << "Fatal Error: " << errorBlob->GetBufferPointer() << endl;
		return 0;
	}

	// Compile the shader into bytecode.
	if(FAILED(D3DCompile( shaderBlob->GetBufferPointer(),  shaderBlob->GetBufferSize(), path.c_str(), NULL, NULL, "DefaultTechnique", "fx_5_0", D3DCOMPILE_DEBUG, 0, &shaderFinalBlob, &errorBlob ))) {
		cout << (char *)errorBlob->GetBufferPointer() << endl;
		return 0;
	}

	ofstream file (outpath.c_str(), ios::out|ios::binary|ios::ate);
	if(!file.is_open()) {
		cout << "Fatal Error: failed to open file for writing" << endl;
		return 0;
	}

	file.write( (const char *)shaderFinalBlob->GetBufferPointer(), shaderFinalBlob->GetBufferSize() );

	file.close();

	return 0;
}